/*
 * Copyright (c) 2005 by IJ Soft
 *
 * This software is private property owned by IJ Soft,
 * disclosure or use of the code without written aggrement
 * is forbiden to any party.
 *
 * Under no circunstance IJ Soft takes any responsability
 * of direct and indirect damage caused by this software,
 * including loss of productivity and/or money.
 */

#region Using directives

using System;
using System.Collections.Generic;
using System.Text;
using System.Reflection;

#endregion

namespace PowerControl
{
    /// <summary>
    /// A lazy allocator that creates the object the first time a reference to the singleton is required, it is thread safe using a lock over the type parameter.
    /// </summary>
    public class LazyAllocator<T> : Allocator<T> where T : class
    {
        /// <summary>
        /// The constructor of the LazyAllocator
        /// </summary>
        private LazyAllocator()
        { }

        private T instance;

        /// <summary>
        /// The instance property creates the singleton object upon the first request.
        /// </summary>
        /// <remarks>The allocator ensure the thread safety using a lock and it enforces the Singleton uniqueness property.</remarks>
        public override T Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (typeof(T))
                    {
                        if (instance == null)
                        {
                            ConstructorInfo constructor = typeof(T).GetConstructor(BindingFlags.Instance | BindingFlags.NonPublic, null, new Type[0], new ParameterModifier[0]);
                            if (constructor == null)
                                throw new Exception( "The object that you want to singleton doesnt have a private/protected constructor so the property cannot be enforced.");

                            try
                            {
                                instance = constructor.Invoke(new object[0]) as T;
                            }
                            catch (Exception e)
                            {
                                throw new Exception("The LazySingleton couldnt be constructed, check if the type T has a default constructor", e);
                            }
                        }
                    }
                }
                return instance;
            }
        }


        public override void Dispose()
        {
            this.instance = null;
            GC.SuppressFinalize(this);
        }
    }
}
